package cn.xllyd.service;

import cn.xllyd.doc.Item;
import cn.xllyd.repository.ItemRepository;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ItemService {
    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;

    /**
     * 聚合查询
     * @param search
     * @return
     */
    public Map<String, List<String>> searchGroupByBrand(String search) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 构建查询条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", search));
        // 聚合
        queryBuilder.addAggregation(AggregationBuilders.terms("groupByBrand").field("brand"));
        // 执行聚合查询
        AggregatedPage<Item> itemPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
        // 解析聚合结果
        StringTerms agg = (StringTerms) itemPage.getAggregation("groupByBrand");
        // 获取桶
        List<StringTerms.Bucket> buckets = agg.getBuckets();
        // 定义一个map收集聚合结果
        Map<String, List<String>> map = new HashMap<>();
        // 遍历
        buckets.forEach(bucket -> {
            // 获取桶中的key，即品牌名称
            String brandName = bucket.getKeyAsString();
            // 获取桶中的文档数量
            long count = bucket.getDocCount();
            System.out.println(brandName + "，共" + count + "台");
            // 获取子聚合结果：桶中的分类名称
            Map<String, Aggregation> subAggregationMap = bucket.getAggregations().asMap();
            ParsedStringTerms categoryAgg = (ParsedStringTerms) subAggregationMap.get("groupByCategory");
            List<String> categoryNames = categoryAgg.getBuckets().stream().map(StringTerms.Bucket::getKeyAsString).collect(Collectors.toList());
            map.put(brandName, categoryNames);
        });
        return map;
    }

    /**
     * 高亮查询
     * @param search
     * @return
     */
    public List<Map<String, Object>> searchHighlight(String search) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 构建查询条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", search));
        // 构建高亮
        queryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        queryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em>").postTags("</em>"));
        // 执行查询
        AggregatedPage<Item> itemPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
        // 解析结果
        List<Map<String, Object>> list = new ArrayList<>();
        itemPage.getContent().forEach(item -> {
            // 封装结果
            Map<String, Object> map = new HashMap<>();
            map.put("id", item.getId());
            map.put("brand", item.getBrand());
            map.put("category", item.getCategory());
            map.put("price", item.getPrice());
            map.put("images", item.getImages());
            // 解析高亮
            Map<String, HighlightField> highlightFields = itemPage.getHighlightFields();
            if (highlightFields != null && highlightFields.size() > 0) {
                map.put("title", highlightFields.get("title").getFragments()[0].string());
            } else {
                map.put("title", item.getTitle());
            }
            list.add(map);
        });
        return list;
    }
}